<template>
  <div>
    <!-- 1 -->
    <h1>{{msg}}</h1>
    <div>默认的 count: {{state.count}} </div>
    <div>默认的 count: {{state.double}} </div>
    <button @click="increment">增加</button>
    <div style="padding: 20px 0;">
      <hr>
    </div>
    <!-- 2 -->
    <div>ref: {{count}}</div>
    <div>reactive: {{state2.count}} || {{obj.name}}</div>
    <div>结构 reactive: {{name}} || {{age}}</div>
    <div style="padding: 20px 0;">
      <hr>
    </div>
    <!-- 3 -->
    <input type="text" ref="root" value="ref使用例子" />
    <div style="padding: 20px 0;">
      <hr>
    </div>
    <!-- 4 -->
    <div>computed: {{plusOne}}</div>
    <div>computed(get/set): {{plusTwo}}</div>
    <div style="padding: 20px 0;">
      <hr>
    </div>
    <!-- 5 -->
    <div>state3: {{state3.count}}</div>
    <div>state4: {{state4.count.count}}</div>
    <div>ref1: {{ref1}}</div>
    <div>ref2: {{ref2}}</div>
    <button @click="add">添加</button>
    <div style="padding: 20px 0;">
      <hr>
    </div>
    <!-- 6 -->
    <div>watchEffect: {{num}}</div>
    <button @click="addNum">增加</button>
  </div>
</template>
<script setup lang="ts">
import { reactive, computed, defineProps, ref, toRefs, onMounted, watch, watchEffect } from 'vue'

defineProps({
  msg: String
})

type DState = {
  count: number;
  double: number;
}

const state: DState = reactive({
  count: 0,
  double: computed(() => state.count * 2)
})
function increment () {
  state.count++
}

/***
 * 示例二
 * **/
// ref 语法糖
const count = ref(0)
// 响应式数据，若不用语法糖则需要 count.value++
count.value++
// reactive 包裹单独的 ref
const state2 = reactive({
  count
})
// 单独声明响应式对象数据
const obj = reactive({
  name: '大大',
  age: 21
})

// 把 reactice 响应式对象解构出来
const { name, age } = { ...toRefs(obj) }

/***
 * 示例三
 * **/
// ref 会根据传入的数据来指向对应的数据类型
// 若传入一个 null，则会指向 DOM
const root = ref(null)

// 首次渲染挂载完成时，才能获取到真实的 DOM
onMounted(() => {
  // console.log('ref.null:', root.value)
})
/***
 * 示例四
 * **/
const count2 = ref(1)
const count3 = ref(0)
const plusOne = computed(() => count2.value + 2)
// 查看计算属性生成对象
// console.log('coumputed:', plusOne)

// get/set 重新设置计算属性
const plusTwo = computed({
  get: () => count3.value + 2,
  set: (val) => { count3.value = val - 1 }
})
plusTwo.value = Math.random()
/***
 * 示例五
 * **/
const state3 = reactive({
  count: 0
})
// 复杂的响应式对象
const state4 = reactive({
  count: { count: 1 }
})
// 多个ref
const ref1 = ref(2)
const ref2 = ref(3)
/***
 * 参数: 1.数据源, 2.回调, 3.函数参数
 * **/
watch(() => state3.count, (newValue, oldValue) => {
  // console.log('state3 监听的值:', newValue, oldValue)
}, {
  immediate: true
})
// 监听深拷贝
watch(() => state4.count, (newValue, oldValue) => {
  // console.log('state4 监听的值:', newValue.count, oldValue.count)
}, {
  deep: true
})

// 监听多个ref
/***
 * 警告并监听失败
 * **/
// watch([ref1.value, ref2.value], ([newRef1, oldRef1], [newRef2, oldRef2]) => {
//   console.log('ref1:', newRef1, oldRef1)
//   console.log('ref2:', newRef2, oldRef2)
// })
/***
 * 监听成功
 * **/
watch(() => [ref1.value, ref2.value], ([newRef1, oldRef1], [newRef2, oldRef2]) => {
  // console.log('ref1:', newRef1, oldRef1)
  // console.log('ref2:', newRef2, oldRef2)
})
const add = () => {
  state3.count++
  state4.count.count++
  ref1.value++
  ref2.value++
}

/***
 * 示例六
 * **/
const num = ref(1)
onMounted(() => {
  // console.log('onMounted')
})
/**
 * 1. 不需要手动传入依赖
 * 2. 不是 lazy，初始化时就执行分析依赖
 * 3. 无法获取原始值
 * 4. 适合操作异步操作
 * 5. 第一个参数处理副作用
 */
const stop = watchEffect((onInvalidate) => {
  // console.log('watcherEffed 在 onMounted 之前调佣', num.value)
  // 清除副作用
  onInvalidate(() => {
    // console.log('监听后的副作用')
  })
}, {
  // flush: "sync",  // 调用的时机
  onTrigger (e) { // 将在依赖项变更导致副作用被触发时被调用。
    // console.log('onTrigger', e)
  },
  onTrack (e) { // 将在响应式 property 或 ref 作为依赖项被追踪时被调用。
    // console.log('onTrack', e)
  }
})
const addNum = () => {
  num.value++
}
stop()
</script>
<style lang="less" scoped>

</style>
